EMR上でHive on Tezを利用する
本日Amazon EMR release 4.7.0がリリースされました。
Apache Tez 0.8.3 and Apache Phoenix 4.7.0 now available on Amazon EMR
そして、このリリースにApache Tezが含まれていました!Tezは以前EMR上に手動でインストールして動作検証を行ったことがあり、既存のHiveクエリを大幅に高速化出来ることが期待できるためEMR公式リリースを楽しみにしていました!
「Tez on EMRを試してみた」というタイトルで話しました #cmdevio2015G | Developers.IO
ということで、今回はEMR release 4.7.0上でHive on Tezを利用する方法について紹介したいと思います。なお、公式ドキュメントに書かれている[Using Tez]とほぼおなじ内容を試しています *1
Apache Tez - Amazon Elastic MapReduce
前提
以下の環境を前提としています。
- emr-4.7.0 でアプリケーションは Hadoop, Hive, Tez
- ハードウェア構成は m1.medium を 1 台(検証用なのでマスターノードのみ)
- EC2キーペアを設定(SSHで接続して操作するため)
- 東京リージョン
AWS CLIだと以下のようなコマンドになります。KeyName
, SubnetId
, log-uri
をご自身の環境に合わせればそのまま利用できるはずです。
aws emr create-cluster --applications Name=Hadoop Name=Hive Name=Tez \ --ec2-attributes '{"KeyName":"XXXX","InstanceProfile":"EMR_EC2_DefaultRole","SubnetId":"subnet-dXXXX"}' \ --service-role EMR_DefaultRole --enable-debugging --release-label emr-4.7.0 \ --log-uri 's3n://aws-logs-XXXX-ap-northeast-1/elasticmapreduce/' --name 'Hive on Tez with EMR' \ --instance-groups '[{"InstanceCount":1,"InstanceGroupType":"MASTER","InstanceType":"m1.medium","Name":"Master Instance Group"}]' \ --region ap-northeast-1
なお、マネジメントコンソール経由でTezを利用する際は[詳細オプション]を利用する必要があるようでしたのでご注意下さい。
クイックオプション
詳細オプション
実行するクエリ
今回はTezを有効化する方法を紹介することが目的であるため、EMRの公式ドキュメントのチュートリアルに書かれているCloudFrontのログをHiveで集計するHive_CloudFront.q
を従来のMapReduceエンジンとTezエンジンのそれぞれで実行してみたいと思います。なお、途中でエンジンを切り替えるため、チュートリアルの手順通りStepを追加するのではなくて同じ手順をSSHでログインしてHive CLI経由でHiveクエリを実行することとします。
ステップ 3: サンプルデータとスクリプトの準備 - Amazon Elastic MapReduce
cloudfront_logs
テーブルを作成するHiveQLは以下になります。東京リージョン前提であるためHive_CloudFront.q
から変更して、LOCATION
はハードコードしています。
CREATE EXTERNAL TABLE IF NOT EXISTS cloudfront_logs ( Date Date, Time STRING, Location STRING, Bytes INT, RequestIP STRING, Method STRING, Host STRING, Uri STRING, Status INT, Referrer STRING, OS String, Browser String, BrowserVersion String ) ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe' WITH SERDEPROPERTIES ( "input.regex" = "^(?!#)([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+[^\(]+[\(]([^\;]+).*\%20([^\/]+)[\/](.*)$" ) LOCATION 's3://ap-northeast-1.elasticmapreduce.samples/cloudfront/data';
次にクエリです。元々はINSERTする内容になっていましたが、今回はHive CLI経由で直接実行するためSELECT句以下のみ利用します。
SELECT os, COUNT(*) count FROM cloudfront_logs WHERE date BETWEEN '2014-07-05' AND '2014-08-05' GROUP BY os;
Hive on MapReduce
最初は従来のMapReduceエンジン上でHiveクエリを実行したいと思います。マスターノードにSSHでログインしてhive
コマンドでHive CLIを起動します。
$ ssh -i /path/to/XXXX.pem -l hadoop ec2-XXX-XXX-XXX-XXX.ap-northeast-1.compute.amazonaws.com [hadoop@ip-172-31-16-183 ~]$ hive Logging initialized using configuration in file:/etc/hive/conf.dist/hive-log4j.properties hive>
まずはcloudfront_logs
テーブルを作成します。
hive> CREATE EXTERNAL TABLE IF NOT EXISTS cloudfront_logs ( > Date Date, > Time STRING, > Location STRING, > Bytes INT, > RequestIP STRING, > Method STRING, > Host STRING, > Uri STRING, > Status INT, > Referrer STRING, > OS String, > Browser String, > BrowserVersion String > ) > ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe' > WITH SERDEPROPERTIES ( > "input.regex" = "^(?!#)([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+([^ ]+)\\s+[^\(]+[\(]([^\;]+).*\%20([^\/]+)[\/](.*)$" > ) LOCATION 's3://ap-northeast-1.elasticmapreduce.samples/cloudfront/data'; OK Time taken: 18.698 seconds
ではクエリを実行します。
hive> SELECT os, COUNT(*) count FROM cloudfront_logs WHERE date BETWEEN '2014-07-05' AND '2014-08-05' GROUP BY os; Query ID = hadoop_20160603125757_5806ff1d-2d8b-4f60-870a-82614a17bf00 Total jobs = 1 Launching Job 1 out of 1 Number of reduce tasks not specified. Estimated from input data size: 1 In order to change the average load for a reducer (in bytes): set hive.exec.reducers.bytes.per.reducer=<number> In order to limit the maximum number of reducers: set hive.exec.reducers.max=<number> In order to set a constant number of reducers: set mapreduce.job.reduces=<number> Starting Job = job_1464953340211_0001, Tracking URL = http://ip-172-31-16-183.ap-northeast-1.compute.internal:20888/proxy/application_1464953340211_0001/ Kill Command = /usr/lib/hadoop/bin/hadoop job -kill job_1464953340211_0001 Hadoop job information for Stage-1: number of mappers: 1; number of reducers: 1 2016-06-03 12:57:39,857 Stage-1 map = 0%, reduce = 0% 2016-06-03 12:58:17,272 Stage-1 map = 13%, reduce = 0%, Cumulative CPU 15.85 sec 2016-06-03 12:58:32,230 Stage-1 map = 27%, reduce = 0%, Cumulative CPU 25.27 sec 2016-06-03 12:58:35,703 Stage-1 map = 33%, reduce = 0%, Cumulative CPU 27.84 sec 2016-06-03 12:58:39,012 Stage-1 map = 40%, reduce = 0%, Cumulative CPU 30.27 sec 2016-06-03 12:58:47,908 Stage-1 map = 53%, reduce = 0%, Cumulative CPU 38.07 sec 2016-06-03 12:58:54,552 Stage-1 map = 100%, reduce = 0%, Cumulative CPU 43.39 sec 2016-06-03 12:59:09,939 Stage-1 map = 100%, reduce = 100%, Cumulative CPU 45.88 sec MapReduce Total cumulative CPU time: 45 seconds 880 msec Ended Job = job_1464953340211_0001 MapReduce Jobs Launched: Stage-Stage-1: Map: 1 Reduce: 1 Cumulative CPU: 45.88 sec HDFS Read: 629 HDFS Write: 60 SUCCESS Total MapReduce CPU Time Spent: 45 seconds 880 msec OK Android 855 Linux 813 MacOS 852 OSX 799 Windows 883 iOS 794 Time taken: 126.913 seconds, Fetched: 6 row(s)
無事終わりました。コンソールにはお馴染みのMapReduceの進捗状況が表示されています。
Hive on Tez
次に同じクエリをTezエンジンで実行したいと思います。Tezエンジンへの切り替えはHiveのhive.execution.engine
という設定値を変更するだけです。
まずはhive.execution.engine
の初期状態を確認します。
hive> SET hive.execution.engine; hive.execution.engine=mr
mr
つまりMapReduceエンジンになっています。こちらをTezに変更します。
hive> SET hive.execution.engine=tez;
これだけです。この操作でMapReduceエンジンからTezエンジンに切り替わります。クエリを実行する前に設定値が変更されていることを確認します。
hive> SET hive.execution.engine; hive.execution.engine=tez
変更されていますね!では、実際にクエリを実行します。
hive> SELECT os, COUNT(*) count FROM cloudfront_logs WHERE date BETWEEN '2014-07-05' AND '2014-08-05' GROUP BY os; Query ID = hadoop_20160603130808_0a04cd9e-bbe3-4c95-861a-d69c2be073c9 Total jobs = 1 Launching Job 1 out of 1 Status: Running (Executing on YARN cluster with App id application_1464953340211_0002) -------------------------------------------------------------------------------- VERTICES STATUS TOTAL COMPLETED RUNNING PENDING FAILED KILLED -------------------------------------------------------------------------------- Map 1 .......... SUCCEEDED 1 1 0 0 0 0 Reducer 2 ...... SUCCEEDED 1 1 0 0 0 0 -------------------------------------------------------------------------------- VERTICES: 02/02 [==========================>>] 100% ELAPSED TIME: 67.18 s -------------------------------------------------------------------------------- OK Android 855 Linux 813 MacOS 852 OSX 799 Windows 883 iOS 794 Time taken: 92.722 seconds, Fetched: 6 row(s)
全く同じクエリですがターミナルに出力される内容が変わっていることが分かるかと思います。処理時間に関しては 126.9 秒 -> 92.7 秒 なので 3 / 4 程度の時間で実行できていますね!なお、Tezを利用することでどの程度早くなるかはクエリやインスタンスタイプ、インスタンス数によって変わりますので、実際に利用する際はご自身の環境でお試し下さい。
Web UI
YARN ResourceManager Web UIではどのように表示されるのでしょうか。実際に見てみたいと思います。EMR上でSparkのWeb UIにアクセスする方法 | Developers.IOと同じようにSOCKSプロキシを利用してアクセスします。
YARN ResourceManager Web UIにアクセスすると、[Application Type]がそれぞれMAPREDUCE
とTEZ
になっており、Hiveクエリ実行時のエンジンが識別可能なことが分かります。
更に、TEZを実行していたApplicaitonの詳細画面を表示し、[Tracking URL]をクリックします。
すると、TEZのWEB UIが表示されます。EMR上でSparkのWeb UIにアクセスする方法 | Developers.IOでもそうでしたが、各YARN ApplicaitonのWEB UIを表示する方法は一貫しているようですね。
なおTezに関してはSparkと異なり、マスターノードのpublic DNSからでも直接Web UIにアクセスできるようになっていました。アクセスする際はhttp://masterDNS:8080/tez-ui
をブラウザのアドレスバーに入力して下さい。
最初からTezエンジンを利用する
公式ドキュメントに書かれている通り、EMRクラスタ起動時に--configurations
オプションを利用してhive-site.xml
のhive.execution.engine
の値を変更します。
Apache Tez - Amazon Elastic MapReduce
今回の起動コマンドの場合であれば6行目を追加する形になります。
aws emr create-cluster --applications Name=Hadoop Name=Hive Name=Tez \ --ec2-attributes '{"KeyName":"XXXX","InstanceProfile":"EMR_EC2_DefaultRole","SubnetId":"subnet-dXXXX"}' \ --service-role EMR_DefaultRole --enable-debugging --release-label emr-4.7.0 \ --log-uri 's3n://aws-logs-XXXX-ap-northeast-1/elasticmapreduce/' --name 'Hive on Tez with EMR' \ --instance-groups '[{"InstanceCount":1,"InstanceGroupType":"MASTER","InstanceType":"m1.medium","Name":"Master Instance Group"}]' \ --configurations '[{"Classification":"hive-site","Properties":{"hive.execution.engine":"tez"},"Configurations":[]}]' \ --region ap-northeast-1
Tezのインストール状況の確認
ちょっと寄り道して、TezがどのようにEMR上にインストールされているか確認したいと思います。
最初はTezのバイナリがHDFS上に配備されているか確認します。やはり配備されているようですね。
[hadoop@ip-172-31-16-183 ~]$ hadoop fs -ls /apps/tez Found 1 items -rw-r--r-- 1 root hadoop 16391028 2016-06-03 11:32 /apps/tez/tez.tar.gz
次にtez-site.xml
を探してみたいと思います。予想通り/etc/tez/conf/tez-site.xml
にありました。
[hadoop@ip-172-31-16-183 ~]$ ll /etc/tez/conf/tez-site.xml -rw-r--r-- 1 root root 1869 6月 3 11:31 /etc/tez/conf/tez-site.xml
最後にHADOOP_CLASSPATH
への追加です。こちらは/etc/hadoop/conf/hadoop-env.sh
内で行われていました。
[hadoop@ip-172-31-16-183 ~]$ grep -i tez /etc/hadoop/conf/hadoop-env.sh # tez environment, needed to enable tez export TEZ_CONF_DIR=/etc/tez/conf export TEZ_JARS=/usr/lib/tez # Add tez into HADOOP_CLASSPATH export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:${TEZ_CONF_DIR}:${TEZ_JARS}/*:${TEZ_JARS}/lib/*
ということで、公式のインストール手順通り素直にインストールしてるみたいでした。
Apache Tez – Install and Deployment Instructions
最後に
ということで、EMR上でのHive on Tezの利用方法の紹介でした。EMR release 4.7.0を利用すれば1箇所設定を変えるだけで利用できますし、それだけで処理時間を短縮したり、同じ処理時間で良いなら例えばインスタンス数を減らすことでコスト削減できる可能性がありますのでぜひ試してみてはいかがでしょうか。
脚注
- ほぼ書き終えたタイミングで気付きました。。 ↩